﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Web.Http.OData.Batch;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;
using Disco.Ontology.Helper;
using Disco.Web.Api.Controllers.Dynamic;
using Microsoft.Data.Edm;

namespace Disco.Web.Api
{
    public static class ODataConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            modelBuilder.AddOntologyEntities();

            IEdmModel model = modelBuilder.GetEdmModel();
            config.Routes.MapODataRoute(
                routeName: "ODataRoute", 
                routePrefix: "odata", 
                model: model, 
                batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));

            var queryAttribute = new QueryableAttribute()
            {
                MaxTop = 25,
                MaxExpansionDepth = 5,
                AllowedArithmeticOperators = AllowedArithmeticOperators.None
            };
            config.EnableQuerySupport(queryAttribute);

            // TODO: As a Developer I want to decouple the DynamicAssemblyResolver from ODataModelBuilder so that the necessary EntitySet collection e.g. could be resolved by DI.
            DynamicAssemblyResolver assemblyResolver = new DynamicAssemblyResolver(modelBuilder.EntitySets);
            config.Services.Replace(typeof(IAssembliesResolver), assemblyResolver);
        }

        private static void AddOntologyEntities(this ODataModelBuilder modelBuilder)
        {
            foreach (var entitySet in OntologyContextHelper.GetEntitySetInfos())
            {
                var baseTypeName = entitySet.Type.BaseType.Name;
                if (!baseTypeName.Equals(typeof(object).Name))
                {
                    if (modelBuilder.EntitySets.Count(x => x.EntityType.Name.Equals(baseTypeName)).Equals(0))
                    {
                        var baseTypeConfig = modelBuilder.AddEntity(entitySet.Type.BaseType);
                        modelBuilder.AddEntitySet(baseTypeName + "s", baseTypeConfig);
                    }
                }

                if (modelBuilder.EntitySets.Count(x => x.ClrType.Equals(entitySet.Type)).Equals(0))
                {
                    var entityTypeConfig = modelBuilder.AddEntity(entitySet.Type);
                    var entitySetConfig = modelBuilder.AddEntitySet(entitySet.Name, entityTypeConfig);
                }
            }
        }
    }
}